#include "ohos_screen_capturer.h"
#include "common_video/ohos/ohos_egl_context_manager.h"
#include "rtc_base/logging.h"

#include "third_party/libyuv/include/libyuv/convert.h"
#include "common_video/libyuv/include/webrtc_libyuv.h"
#include "common_video/ohos/ohos_display_manager.h"
#include <native_image/native_image.h>
#include <native_buffer/native_buffer.h>

#include <window_manager/oh_display_manager.h>

namespace webrtc {
const int32_t kAudioSampleRate = 48000;
const int kAudioNumChannels = 1;

static void OnError(OH_AVScreenCapture *capture, int32_t error_code, void *user_data) {
    (void)capture;
    (void)error_code;
    (void)user_data;
    RTC_LOG_F(LS_ERROR) << "ScreenCapturerOhos OnError error_code :" << error_code;
    auto screen_capture = static_cast<ScreenCapturerOhos *>(user_data);
    if(screen_capture) {
        screen_capture->OnScreenError(error_code);
    }
}

static void OnStateChange(struct OH_AVScreenCapture *capture, OH_AVScreenCaptureStateCode state_code,
                                        void *user_data) {
    RTC_LOG_F(LS_INFO) << "ScreenCapturerOhos OnStateChange state_code :" << state_code;
    auto screen_capture = static_cast<ScreenCapturerOhos *>(user_data);
    if (screen_capture) {
        screen_capture->OnScreenStateChange(state_code);
    }
}

static void OnBufferAvailable(OH_AVScreenCapture *capture, OH_AVBuffer *buffer,
                                            OH_AVScreenCaptureBufferType buffer_type, int64_t timestamp,
                                            void *user_data) {
    auto screen_capture = static_cast<ScreenCapturerOhos *>(user_data);
    if (screen_capture) {
        screen_capture->OnScreenBufferAvailable(buffer,buffer_type,timestamp);
    }
}

ScreenCapturerOhos::ScreenCapturerOhos(CaptureType type, bool enable_auto_rotation)
  : fps_(0)
  , last_frame_time_(std::chrono::steady_clock::now())
  , debug_log_counter_(0)
  , captureType_(type)
  , capture_state_(CaptureState::CS_STOPPED)
  , enable_auto_rotation_(enable_auto_rotation) {

    if (enable_auto_rotation_) {
        webrtc::DisplayManagerOhos::GetInstance()->Init();
    }
    RTC_LOG_T(LS_INFO) << "ScreenCapturerOhos::Ctor auto_rotation:" << enable_auto_rotation_;
}

ScreenCapturerOhos::~ScreenCapturerOhos() {
    RTC_LOG_T(LS_INFO) << "ScreenCapturerOhos::dtor";
    if (IsRunning()) {
        Stop();
    }
    Release();
}

bool ScreenCapturerOhos::Init() {
    RTC_LOG_T(LS_INFO) << "ScreenCapturerOhos::Init";
    screen_capture_ = OH_AVScreenCapture_Create();
    // set callback
    OH_AVScreenCapture_SetErrorCallback(screen_capture_, OnError, this);
    OH_AVScreenCapture_SetStateCallback(screen_capture_, OnStateChange, this);
    OH_AVScreenCapture_SetDataCallback(screen_capture_, OnBufferAvailable, this);
    RTC_LOG_T(LS_INFO) << "ScreenCapturerOhos::Init end";
    return true;
}

CaptureState ScreenCapturerOhos::Start(const cricket::VideoFormat& capture_format) {
    if(!screen_capture_) {
        RTC_LOG(LS_ERROR) << "ScreenCapturerOhos::Start failed due to create VideoCapture";
        return CaptureState::CS_FAILED;
    }

    if(IsRunning()) {
        RTC_LOG(LS_WARNING) << "ScreenCapturerOhos::Start failed, capturer is already running";
        return CaptureState::CS_RUNNING;
    }
    int32_t width_screen, height_screen;
    auto err =  OH_NativeDisplayManager_GetDefaultDisplayWidth (&width_screen);
    if(err != NativeDisplayManager_ErrorCode::DISPLAY_MANAGER_OK){
        RTC_LOG(LS_WARNING) << "OH_NativeDisplayManager_GetDefaultDisplayWidth err ";
    }
    err = OH_NativeDisplayManager_GetDefaultDisplayHeight (&height_screen);
    if(err != NativeDisplayManager_ErrorCode::DISPLAY_MANAGER_OK){
        RTC_LOG(LS_WARNING) << "OH_NativeDisplayManager_GetDefaultDisplayHeight err ";
    }
    RTC_LOG_T(LS_INFO) << "ScreenCapturerOhos::width_screen height_screen: " << width_screen << "x" << height_screen;
    float screen_ratio = static_cast<float>(width_screen) / height_screen;
    float capture_ratio = static_cast<float>(capture_format.width) / capture_format.height;
    capture_format_ = capture_format;
    if(screen_ratio > capture_ratio){
        capture_format_.height = static_cast<int>(capture_format_.width * screen_ratio);
    }
    else{
        capture_format_.width = static_cast<int>(capture_format_.height*screen_ratio);
    }

    int width = capture_format_.width;
    int height = capture_format_.height;
    fps_ = cricket::VideoFormat::IntervalToFps(capture_format_.interval);
    RTC_LOG_T(LS_INFO) << "ScreenCapturerOhos::Start " << width << "x" << height << "@" << fps_;

    OH_VideoCaptureInfo video_capture_info = {
        .videoFrameWidth = width, .videoFrameHeight = height, .videoSource = OH_VIDEO_SOURCE_SURFACE_RGBA}; //TODO：验证是否支持YUV

    OH_VideoInfo video_info = {
        .videoCapInfo = video_capture_info, 
    };

    OH_AudioCaptureInfo audio_capture_info = {.audioSampleRate = kAudioSampleRate, .audioChannels = kAudioNumChannels, .audioSource = OH_ALL_PLAYBACK}; //TODO: 测试录制手机声音

    OH_AudioInfo audio_info = {
        .innerCapInfo = audio_capture_info,
    };

    OH_AVScreenCaptureConfig config = {.captureMode = OH_CAPTURE_HOME_SCREEN,
                                       .dataType = OH_ORIGINAL_STREAM,
                                       .audioInfo = audio_info,
                                       .videoInfo = video_info};
    int ret = OH_AVScreenCapture_Init(screen_capture_, config);
    if (ret != AV_SCREEN_CAPTURE_ERR_OK) {
        RTC_LOG_T(LS_ERROR) << "ScreenCapturerOhos::Start OH_AVScreenCapture_Init failed: " << ret;
        return CaptureState::CS_FAILED;
    }

    if (captureType_ == CaptureType::SURFACE) {
        if (InitRenderContext() == false) {
            RTC_LOG_T(LS_ERROR) <<"ScreenCapturerOhos::Start InitRenderContext failed";
            return CaptureState::CS_FAILED;
        }

        if (CreateNativeImage() == false) {
            RTC_LOG_T(LS_ERROR) <<"ScreenCapturerOhos::Start CreateNativeImage failed";
            return CaptureState::CS_FAILED;
        }

        if (CreateNativeWindow() == false) {
            RTC_LOG_T(LS_ERROR) <<"ScreenCapturerOhos::Start CreateNativeWindow failed";
            return CaptureState::CS_FAILED;
        }
        int32_t ret = OH_AVScreenCapture_StartScreenCaptureWithSurface(screen_capture_, nativeWindow_);
        if (ret != AV_SCREEN_CAPTURE_ERR_OK) {
            RTC_LOG_T(LS_ERROR) <<"ScreenCapturerOhos::Start "
                                << "OH_AVScreenCapture_StartScreenCaptureWithSurface failed" << ret;
            Release();
            return CaptureState::CS_FAILED;
        }
    } else {
        ret = OH_AVScreenCapture_StartScreenCapture(screen_capture_);
        // OH_AVScreenCapture_SetMicrophoneEnabled(screen_capture_, true); 
        if (ret != AV_SCREEN_CAPTURE_ERR_OK) {
            RTC_LOG_T(LS_ERROR) << "ScreenCapturerOhos::Start OH_AVScreenCapture_StartScreenCapture failed: " << ret;
            return CaptureState::CS_FAILED;
        }
    }
    capture_state_ = CaptureState::CS_RUNNING;
    if (enable_auto_rotation_) {
        init_rotation_  = int(webrtc::DisplayManagerOhos::GetInstance()->GetDefaultDisplayRotation());
    }
    RTC_LOG_T(LS_INFO) << "ScreenCapturerOhos::Start " << width << "x" << height << "@" << fps_ << " init_rotation:" << init_rotation_;
    return CaptureState::CS_STARTING;
}

void ScreenCapturerOhos::Stop() {
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::Stop";
    if (screen_capture_ && IsRunning()) {
        int ret = OH_AVScreenCapture_StopScreenCapture(screen_capture_);
        if (ret != AV_SCREEN_CAPTURE_ERR_OK) {
            RTC_LOG_T(LS_ERROR) << "ScreenCapturerOhos::Stop OH_AVScreenCapture_StopScreenCapture failed: " << ret;
        }   
    } else {
        RTC_LOG(LS_WARNING) << "ScreenCapturerOhos::Stop capturer not runing";
        return;
    }
    {
        webrtc::MutexLock lock(&mutex_);
        if (external_audio_source_) {
            external_audio_source_->Reset();
        }
    }
    capture_state_ = CaptureState::CS_STOPPED;
}


void ScreenCapturerOhos::SetCallback(ScreenCallback *screen_callback) {
  RTC_LOG(LS_INFO) << "ScreenCapturerOhos::SetCallback " << screen_callback;
  screen_callback_ = screen_callback;
}

void ScreenCapturerOhos::SetFrameRotation(int rotation) {
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::SetFrameRotation " << rotation;
    rotation_ = rotation;
}

bool ScreenCapturerOhos::IsRunning() {
    return capture_state_ == CaptureState::CS_RUNNING ? true : false;
}

void ScreenCapturerOhos::Release() {
    if(screen_capture_) {
        RTC_LOG(LS_INFO) << "ScreenCapturerOhos::Release";
        OH_AVScreenCapture_Release(screen_capture_);
        screen_capture_ = nullptr;
    }

    // Destroy NativeWindow NativeImage RenderContext
    if (captureType_ == CaptureType::SURFACE) {
        DestroyNativeWindow();
        DestroyNativeImage();
        DestroyRenderContext();
    }
    screen_capture_ = nullptr;

}

void ScreenCapturerOhos::OnScreenError(int32_t error_code) {
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::OnScreenError error_code " << error_code;
}

void ScreenCapturerOhos::OnScreenStateChange(OH_AVScreenCaptureStateCode state_code) {
    switch (state_code) {
        case OH_SCREEN_CAPTURE_STATE_STARTED:
            RTC_LOG(LS_INFO) << "ScreenCapturerOhos::OnScreenStateChange OH_SCREEN_CAPTURE_STATE_STARTED";
            break;
        case OH_SCREEN_CAPTURE_STATE_STOPPED_BY_USER:
            RTC_LOG(LS_INFO) << "ScreenCapturerOhos::OnScreenStateChange OH_SCREEN_CAPTURE_STATE_STOPPED_BY_USER";
            break;
        case OH_SCREEN_CAPTURE_STATE_CANCELED:
            RTC_LOG(LS_INFO) << "ScreenCapturerOhos::OnScreenStateChange OH_SCREEN_CAPTURE_STATE_CANCELED";
            break;
        case OH_SCREEN_CAPTURE_STATE_INTERRUPTED_BY_OTHER:
            RTC_LOG(LS_INFO) << "ScreenCapturerOhos::OnScreenStateChange OH_SCREEN_CAPTURE_STATE_INTERRUPTED_BY_OTHER";
        case OH_SCREEN_CAPTURE_STATE_STOPPED_BY_CALL:
            RTC_LOG(LS_INFO) << "ScreenCapturerOhos::OnScreenStateChange OH_SCREEN_CAPTURE_STATE_STOPPED_BY_CALL";
            break;
        default:
            RTC_LOG(LS_INFO) << "ScreenCapturerOhos::OnScreenStateChange state code:" << (int)state_code;
            break;
    }
}

void ScreenCapturerOhos::OnScreenBufferAvailable(OH_AVBuffer *buffer,OH_AVScreenCaptureBufferType buffer_type, int64_t timestamp) {
    if (buffer_type == OH_SCREEN_CAPTURE_BUFFERTYPE_VIDEO) {

        std::chrono::milliseconds min_interval = std::chrono::milliseconds(1000 / fps_);
        std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
        std::chrono::duration<double, std::milli> time_span = now - last_frame_time_;

        if (time_span < min_interval) {
            return; // drop frame
        }

        last_frame_time_ = now;

        // 处理视频buffer
        uint8_t* receiver_buffer = OH_AVBuffer_GetAddr(buffer);
        if (receiver_buffer == nullptr) {
            RTC_LOG(LS_INFO) << "ScreenCapturerOhos::OnScreenBufferAvailable OH_AVBuffer_GetAddr failed, buffer_type: " << buffer_type;
            return;
        }
        
        OH_NativeBuffer *native_buffer = OH_AVBuffer_GetNativeBuffer(buffer);
        if (native_buffer == nullptr) {
            RTC_LOG(LS_INFO) << "ScreenCapturerOhos::OnScreenBufferAvailable OH_AVBuffer_GetNativeBuffer failed, buffer_type: " << buffer_type;
            return;
        }
        
        OH_NativeBuffer_Config config;
        OH_NativeBuffer_GetConfig(native_buffer, &config);
        int width = config.width;
        int height = config.height;
        int stride = config.stride;
        rtc::scoped_refptr<webrtc::I420Buffer> i420_buffer = webrtc::I420Buffer::Create(width, height);
        // 设置时为RGBA，使用RGBA转换颜色不对，使用ABGR转换是正常的。（可能是大小端序的原因）
        libyuv::ABGRToI420(receiver_buffer, stride, i420_buffer.get()->MutableDataY(),
                        i420_buffer.get()->StrideY(), i420_buffer.get()->MutableDataU(), i420_buffer.get()->StrideU(),
                        i420_buffer.get()->MutableDataV(), i420_buffer.get()->StrideV(), width, height);
        if (enable_auto_rotation_) {
            NativeDisplayManager_Rotation displayRotation = webrtc::DisplayManagerOhos::GetInstance()->GetDefaultDisplayRotation();
            int finalRotation = (int(displayRotation) - init_rotation_ + 4) % 4;
            switch(finalRotation) {
              case 0:
                rotation_ = 0;
                break;
              case 1:
                rotation_ = 90;
                break;
              case 2:
                rotation_ = 180;
                break;
              case 3:
                rotation_ = 270;
                break;
            }
        }  
        webrtc::VideoFrame video_frame = webrtc::VideoFrame::Builder()
                                        .set_video_frame_buffer(i420_buffer)
                                        .set_timestamp_rtp(0)
                                        .set_timestamp_ms(rtc::TimeMillis())
                                        .set_rotation(webrtc::VideoRotation(rotation_))
                                        .build();
        OH_NativeBuffer_Unreference(native_buffer);
        debug_log_counter_ ++;
        if (debug_log_counter_%fps_ == 1 || fps_<= 1) {
            RTC_LOG(LS_INFO) << "ScreenCapturerOhos::OnScreenBufferAvailable, videoframe, w:" << width << ", h:" << height
                             << ", cnt:" << debug_log_counter_;
        }
        if (screen_callback_) {
            screen_callback_->DidCaptureVideoFrame(video_frame, width, height);
        }

    } else if (buffer_type == OH_SCREEN_CAPTURE_BUFFERTYPE_AUDIO_INNER) {
        // inner buffer
        const int bytes_per_sample = sizeof(int16_t) * kAudioNumChannels;
        const int samples_per_channel_10ms = kAudioSampleRate / 100;
        const size_t num_elements_10ms = samples_per_channel_10ms * kAudioNumChannels;

        uint8_t* receiver_buffer = OH_AVBuffer_GetAddr(buffer);
        if (receiver_buffer == nullptr) {
            RTC_LOG(LS_INFO) << "ScreenCaptureOhos::OnScreenBufferAvailable OH_AVBuffer_GetAddr failed, buffer_type: " << buffer_type;
            return;
        }
        
        OH_AVCodecBufferAttr buffer_info;
        OH_AVBuffer_GetBufferAttr(buffer, &buffer_info);

        captured_audio_buffer_.AppendData((int16_t*)receiver_buffer, buffer_info.size / sizeof(int16_t));
        while (captured_audio_buffer_.size() >= num_elements_10ms) {
            {
                webrtc::MutexLock lock(&mutex_);
                if (external_audio_source_) {
                    external_audio_source_->DeliverFrame((unsigned char *)captured_audio_buffer_.data(),
                                                    num_elements_10ms,
                                                    bytes_per_sample,
                                                    kAudioNumChannels,
                                                    kAudioSampleRate,
                                                    0);
                }
            }
            memmove(captured_audio_buffer_.data(), captured_audio_buffer_.data() + num_elements_10ms,
                    (captured_audio_buffer_.size() - num_elements_10ms) * sizeof(int16_t));
            captured_audio_buffer_.SetSize(captured_audio_buffer_.size() - num_elements_10ms);
        }
    } else if (buffer_type == OH_SCREEN_CAPTURE_BUFFERTYPE_AUDIO_MIC) {
        // 处理麦克风buffer
        RTC_LOG(LS_INFO) << "audio mic not supported.";
    }
}


void ScreenCapturerOhos::OnNativeImageFrameAvailable(void *data)
{
    ScreenCapturerOhos* desktop = static_cast<ScreenCapturerOhos*>(data);
    desktop->OnNativeFrameAvailable();
    RTC_LOG(LS_VERBOSE) << "ScreenCapturerOhos::OnNativeImageFrameAvailable called";
}

int32_t ScreenCapturerOhos::OnNativeFrameAvailable()
{
    int32_t ret;
    gl_context_->MakeCurrent(eglSurface_);
    RTC_LOG(LS_VERBOSE) << "ScreenCapturerOhos::OnNativeFrameAvailable MakeCurrent " << GetEglErrorString();
    {
        std::lock_guard<std::mutex> lock(*(OhosEGLContextManager::GetInstance().GetTextureMutex(nativeImageTextureID_)));
        ret = OH_NativeImage_UpdateSurfaceImage(nativeImage_);
        RTC_LOG(LS_VERBOSE) << "ScreenCapturerOhos::OnNativeFrameAvailable OH_NativeImage_UpdateSurfaceImage "
                         << GetGLErrorString();
        RTC_LOG(LS_VERBOSE) << "ScreenCapturerOhos::OnNativeFrameAvailable ImageTextureID = " << nativeImageTextureID_;
    }

    gl_context_->MakeCurrent();
    RTC_LOG(LS_VERBOSE) << "ScreenCapturerOhos::OnNativeFrameAvailable MakeEmptyCurrent " << GetEglErrorString();

    if (ret != 0) {
        RTC_LOG(LS_ERROR) << "ScreenCapturerOhos::OnNativeFrameAvailable OH_NativeImage_UpdateSurfaceImage failed, ret: " << ret;
        return -1;
    }

    // create video frame
    int width = capture_format_.width;
    int height = capture_format_.height;
    rtc::scoped_refptr<OhosVideoBuffer> textureBuffer = OhosVideoBuffer::Create(width, height, textureBuffer_);
    if (enable_auto_rotation_) {
        NativeDisplayManager_Rotation displayRotation = webrtc::DisplayManagerOhos::GetInstance()->GetDefaultDisplayRotation();
        int finalRotation = (int(displayRotation) - init_rotation_ + 4) % 4;
        switch(finalRotation) {
            case 0:
            rotation_ = 0;
            break;
            case 1:
            rotation_ = 90;
            break;
            case 2:
            rotation_ = 180;
            break;
            case 3:
            rotation_ = 270;
            break;
        }
    }  
    webrtc::VideoFrame video_frame = webrtc::VideoFrame::Builder()
                                       .set_video_frame_buffer(textureBuffer)
                                       .set_timestamp_rtp(0)
                                       .set_timestamp_ms(rtc::TimeMillis())
                                       .set_rotation(webrtc::VideoRotation(rotation_))
                                       .build();

    if (!IsRunning()) {
        return -1;
    }

    std::chrono::milliseconds min_interval = std::chrono::milliseconds(1000 / fps_);
    std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
    std::chrono::duration<double, std::milli> time_span = now - last_frame_time_;
    if (time_span < min_interval) {
        return -1; // drop frame
    }
    last_frame_time_ = now;

    debug_log_counter_ ++;
    if (debug_log_counter_%fps_ == 1 || fps_<= 1) {
        RTC_LOG(LS_INFO) << "ScreenCapturerOhos::OnNativeFrameAvailable, videoframe, w:" << width << ", h:" << height
                         << ", cnt:" << debug_log_counter_;
    }
    if (screen_callback_) {
      screen_callback_->DidCaptureVideoFrame(video_frame, width, height);
    }
    return 0;
}


bool ScreenCapturerOhos::InitRenderContext()
{

    gl_context_ = std::make_unique<EGLRenderContext>();
    auto contextResource = OhosEGLContextManager::GetInstance().GetEGLContextResource();
    if (contextResource == nullptr) {
        RTC_LOG(LS_INFO) << "ScreenCapturerOhos::InitRenderContext GetEGLContextResource failed";
        return false;
    }
    if (!gl_context_->Init(contextResource->eglContext_->GetEGLContext())) {
      RTC_LOG_T(LS_ERROR) << "ScreenCapturerOhos::InitRenderContext init EGL failed!";
      return false;
    }

    // 创建eglSurface_
    int width = capture_format_.width;
    int height = capture_format_.height;
    EGLint pBufferAttributes[] = {EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE};
    eglSurface_ = gl_context_->CreatePBufferEglSurface(pBufferAttributes);
    if (eglSurface_ == EGL_NO_SURFACE) {
        RTC_LOG(LS_INFO) << "ScreenCapturerOhos::InitRenderContext CreateEglSurface " << GetEglErrorString();
        return false;
    }

    return true;
}

int32_t ScreenCapturerOhos::DestroyRenderContext()
{
    if (eglSurface_ != EGL_NO_SURFACE && gl_context_ != nullptr) {
        gl_context_->DestroyEglSurface(eglSurface_);
        eglSurface_ = EGL_NO_SURFACE;
    }
    gl_context_.reset();

    return 0;
}

bool ScreenCapturerOhos::CreateNativeWindow()
{
    nativeWindow_ = OH_NativeImage_AcquireNativeWindow(nativeImage_);
    if (nativeWindow_ == nullptr) {
        RTC_LOG(LS_ERROR) << "ScreenCapturerOhos::CreateNativeWindow OH_NativeImage_AcquireNativeWindow failed";
        return false;
    }

    int width = capture_format_.width;
    int height = capture_format_.height;
    int32_t ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow_, SET_BUFFER_GEOMETRY, width, height);
    if (ret != 0) {
        RTC_LOG(LS_ERROR) << "ScreenCapturerOhos::CreateNativeWindow OH_NativeWindow_NativeWindowHandleOpt failed";
        return false;
    }

    return true;
}

int32_t ScreenCapturerOhos::DestroyNativeWindow()
{
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::DestroyNativeWindow started";
    if (nativeWindow_ != nullptr) {
        OH_NativeWindow_DestroyNativeWindow(nativeWindow_);
        nativeWindow_ = nullptr;
    }
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::DestroyNativeWindow end";
    return 0;
}

bool ScreenCapturerOhos::CreateNativeImage()
{
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::CreateNativeImage started";
    gl_context_->MakeCurrent(eglSurface_);
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::CreateNativeImage MakeCurrent "
                     << GetEglErrorString();

    glGenTextures(1, &nativeImageTextureID_);
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::CreateNativeImage textureID = " << nativeImageTextureID_;
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::CreateNativeImage glGenTextures " << GetGLErrorString();

    glBindTexture(GL_TEXTURE_EXTERNAL_OES, nativeImageTextureID_);
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::CreateNativeImage glBindTexture " << GetGLErrorString();

    // set the texture wrapping parameters
    glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_REPEAT);
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::CreateNativeImage glTexParameteri  " << GetGLErrorString();
    glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_REPEAT);
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::CreateNativeImage glTexParameteri " << GetGLErrorString();

    // set texture filtering parameters
    glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::CreateNativeImage glTexParameteri " << GetGLErrorString();
    glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::CreateNativeImage glTexParameteri " << GetGLErrorString();

    nativeImage_ = OH_NativeImage_Create(nativeImageTextureID_, GL_TEXTURE_EXTERNAL_OES);
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::CreateNativeImage OH_NativeImage_Create " << GetGLErrorString();

    glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::CreateNativeImage glBindTexture " << GetGLErrorString();

    gl_context_->MakeCurrent();
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::CreateNativeImage MakeEmptyCurrent " << GetEglErrorString();

    if (nativeImage_ == nullptr) {
        RTC_LOG(LS_ERROR) << "ScreenCapturerOhos::CreateNativeImage OH_NativeImage_Create failed.";
        return false;
    }

    nativeImageFrameAvailableListener_.context = this;
    nativeImageFrameAvailableListener_.onFrameAvailable = &ScreenCapturerOhos::OnNativeImageFrameAvailable;
    int32_t ret = OH_NativeImage_SetOnFrameAvailableListener(nativeImage_, nativeImageFrameAvailableListener_);
    if (ret != 0) {
        RTC_LOG(LS_ERROR) << "ScreenCapturerOhos::CreateNativeImage OH_NativeImage_SetOnFrameAvailableListener failed, ret is " << ret;
        return false;
    }

    // set textrueBuffer_
    textureBuffer_.textureID = nativeImageTextureID_;
    textureBuffer_.type = OhosBufferType::OES;
    ret = OH_NativeImage_GetTransformMatrix(nativeImage_, textureBuffer_.matrix);
    if (ret != 0) {
        RTC_LOG(LS_ERROR) << "ScreenCapturerOhos::CreateNativeImage OH_NativeImage_GetTransformMatrix failed, ret is " << ret;
        return false;
    }

    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::CreateNativeImage end";
    return true;
}

int32_t ScreenCapturerOhos::DestroyNativeImage()
{
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::DestroyNativeImage start";

    if (nativeImage_ != nullptr) {
        (void)OH_NativeImage_UnsetOnFrameAvailableListener(nativeImage_);
        OH_NativeImage_Destroy(&nativeImage_);
        nativeImage_ = nullptr;
    }

    if (nativeImageTextureID_ != 0U && gl_context_ != nullptr) {
        gl_context_->MakeCurrent(eglSurface_);
        RTC_LOG(LS_INFO) << "ScreenCapturerOhos::DestroyNativeImage MakeCurrent " << GetEglErrorString();

        {
            std::lock_guard<std::mutex> lock(*(OhosEGLContextManager::GetInstance().GetTextureMutex(nativeImageTextureID_)));
            glDeleteTextures(1, &nativeImageTextureID_);
            nativeImageTextureID_ = 0U;
        }

        gl_context_->MakeCurrent();
        RTC_LOG(LS_INFO) << "ScreenCapturerOhos::DestroyNativeImage MakeEmptyCurrent " << GetEglErrorString();
    }

    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::DestroyNativeImage end";
    return 0;
}

void ScreenCapturerOhos::SetAudioSource(ohoswebrtc::OHOSExternalAudioSourceImpl *external_audio_source) {
    RTC_LOG(LS_INFO) << "ScreenCapturerOhos::SetAudioSource " << external_audio_source;
    webrtc::MutexLock lock(&mutex_);
    external_audio_source_ = external_audio_source;
}


} //namespace webrtc